package boot.spring.listener;

import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.EngineServices;
import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.delegate.TaskListener;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ExecutionQuery;
import org.activiti.engine.task.Task;
import org.activiti.spring.SpringConfigurationHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import boot.spring.config.SpringContextHolder;
import boot.spring.service.LeaveService;
import boot.spring.service.SystemService;
/**
 * 任务监听
 * @author Administrator
 *
 *TaskListener的事件：create、assigeneed、complete和delete事件。

              create事件是流程流转到该节点触发的事件。

              assigeneed事件是该任务节点设置了"assigenee"后才会触发的事件,若没有设置assigenee则不会触发此事件

             complete事件是完成时触发

             delete是删除任务时触发。
 */
public class NextTaskListener implements ExecutionListener,TaskListener{
	
		
	/*
	 * private ProcessEngine processEngine;
	 * 
	 * public NextTaskListener() { processEngine =
	 * SpringContextHolder.getBean(ProcessEngine.class); }
	 */	
		
	
	 /**
	  * 任务侦听器：用于在任务相关的事件发生时执行一段java逻辑或者是表达式
     * 任务节点的监听
     * TaskListener类实现
     * 说明: usertask2节点配置了处理人所以触发assignment事件监听，
     * 当任务运转到usertask2的时候触发了create事件。 这里我们也可以得出一个结论：assignment事件比create先执行。
     * 任务完成的时候，触发complete事件，因为任务完成之后，要从ACT_RU_TASK中删除这条记录，所以触发delete事件
     * @param delegateTask
     */
	@Override
	public void notify(DelegateTask delegateTask) {
		delegateTask.getTaskDefinitionKey();
		System.out.println("======DelegateTask========>");
		String eventName = delegateTask.getEventName();
        // ActivitiEventType.PROCESS_STARTED
        if ("create".endsWith(eventName)) {
        	 System.out.println("create=========");
        } else if ("assignment".endsWith(eventName)) {
        	 System.out.println("assignment========");
        } else if ("complete".endsWith(eventName)) {
        	 System.out.println("complete===========");
        } else if ("delete".endsWith(eventName)) {
        	 System.out.println("delete=============");
        }
     // delegateTask 可以操作activiti引擎的一些东西
        // 获取上报人
        Map<String,Object> map = delegateTask.getVariables();
        String  starter = (String) map.get("starter");
        System.out.println("发起人："+starter);
        EngineServices engineServices = delegateTask.getExecution().getEngineServices();
        delegateTask.getProcessInstanceId();
        String id = getNextNode(engineServices,delegateTask.getProcessInstanceId());
        	
        System.out.println("------id----->"+id);
        
        if(!Objects.isNull(starter)) {
        	// 这里指定下一步办理人
//        	delegateTask.setAssignee("xiaoyijingli");
        }
	}
	
    /**
     * 获取当前流程的下一个节点
     * @param procInstanceId
     * @return
     */
    public static String getNextNode(EngineServices engineServices,String procInstanceId){
        // 1、首先是根据流程ID获取当前任务：
        List<Task> tasks = engineServices.getTaskService().createTaskQuery().processInstanceId(procInstanceId).list();
        String nextId = "";
        for (Task task : tasks) {
            RepositoryService rs = engineServices.getRepositoryService();
            // 2、然后根据当前任务获取当前流程的流程定义，然后根据流程定义获得所有的节点：
            ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl) rs)
                    .getDeployedProcessDefinition(task.getProcessDefinitionId());
            List<ActivityImpl> activitiList = def.getActivities(); // rs是指RepositoryService的实例
            // 3、根据任务获取当前流程执行ID，执行实例以及当前流程节点的ID：
            String excId = task.getExecutionId();
            RuntimeService runtimeService = engineServices.getRuntimeService();
            ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(excId)
                    .singleResult();
            String activitiId = execution.getActivityId();
            // 4、然后循环activitiList
            // 并判断出当前流程所处节点，然后得到当前节点实例，根据节点实例获取所有从当前节点出发的路径，然后根据路径获得下一个节点实例：
            for (ActivityImpl activityImpl : activitiList) {
                String id = activityImpl.getId();
                if (activitiId.equals(id)) {
                   System.out.println("当前任务：" + activityImpl.getProperty("name")); // 输出某个节点的某种属性
                    List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();// 获取从某个节点出来的所有线路
                    for (PvmTransition tr : outTransitions) {
                        PvmActivity ac = tr.getDestination(); // 获取线路的终点节点
                        System.out.println("下一步任务任务：" + ac.getProperty("name"));
                        nextId = ac.getId();
                    }
                    break;
                }
            }
        }
        return nextId;
    }
	/**
     * 监听开始结束
     * 
     * 选中一条连线。

		节点的开始和结束。
		
		网关的开始和结束。
		
		中间事件的开始和结束。
		
		开始时间结束或结束事件开始
     * ExecutionListener类的实现
     * @param execution
     */
	@Override
	public void notify(DelegateExecution execution) throws Exception {
		System.out.println("======DelegateExecution========>");
		EngineServices engineServices = execution.getEngineServices();
		RuntimeService runtimeService = engineServices.getRuntimeService();
		 String eventName = execution.getEventName();
		if ("start".equals(eventName)) {
            // 流程开始
            System.out.println("start......");
        } else if ("end".equals(eventName)) {
            // 流程结束
        	System.out.println("end......");
        } else if ("take".equals(eventName)) {
            // 连线监听器
        	System.out.println("take......");
        }
	}

}
